package logger.sd.server.service;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;

import logger.sd.protocol.LRP;
import logger.sd.server.LoggingServer;
import logger.sd.server.ServerConfiguration;

/**
 * Replicador
 * 
 * @author wendell
 * 
 */
public class SimpleReplicator implements Replicator {

	private Integer conit;
	private LoggingServer server;
	private ServerConfiguration config;
	private String fileBufferName;

	public SimpleReplicator(LoggingServer server) {
		this.server = server;
		this.config = server.getConfig();
		this.fileBufferName = config.getLogFilename() + " - replica";
		this.conit = config.getConit();
	}

	/**
	 * Insere uma requisicao no Buffer
	 */
	@Override
	public synchronized void insertBuffer(String code, String request) {

		// Soh replica se estah num token ring, se nao fui eu quem mandou a
		// mensagem e se nao eh uma msg de token
		if (config.getNextPortServer() != 0
				&& !code.equals(LRP.TOKEN.getMessage())
				&& !code.equals(LRP.TOKENARRIVE.getMessage())) {

			FileWriter writer;
			try {
				writer = new FileWriter(new File(fileBufferName), true);
				PrintWriter out = new PrintWriter(writer, true);
				out.println(code + ':' + request);
				out.close();
				writer.close();

				server.addChange();

				if (server.getChanges() >= conit) {
					this.send();
				}

			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	/**
	 * Envia mensagem de replicacao para o proximo servidor
	 */
	@Override
	public void send() {
		try {
			File file = new File(fileBufferName);
			FileReader reader = new FileReader(file);
			BufferedReader br = new BufferedReader(reader);
			String request;

			while ((request = br.readLine()) != null) {
				replyRequest(request);
			}

			reader.close();
			file.delete();
			server.clearChanges();

		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}

	}

	/**
	 * Envia a requisicao para o proximo servidor
	 * 
	 * @param request
	 */
	private synchronized void replyRequest(String request) {

		try {

			for (String other : config.getOthersServers()) {
				Socket nextServerSocket;
				String[] div = other.split(":");

				// div[0]=host. div[1]=port
				nextServerSocket = new Socket(div[0], Integer.parseInt(div[1]));

				BufferedReader inFromServer = new BufferedReader(
						new InputStreamReader(nextServerSocket.
								getInputStream()));

				DataOutputStream outToServer = new DataOutputStream(
						nextServerSocket.getOutputStream());

				outToServer.writeBytes(LRP.REPLY.getMessage() + ':' + request
						+ '\n');

				String resp = inFromServer.readLine();

				if (!resp.equals(LRP.okMessage())
						&& !resp.equals(LRP.bufferMessage())) {
					System.err.println("Erro de replicacao: "+resp);
				}
				
				nextServerSocket.close();
			}

		} catch (UnknownHostException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}

	}
	
	/**
	 * 
	 * @return
	 */
	public String getFileBufferName() {
		return this.fileBufferName;
	}

}
